package com.ycy.lock;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.CountDownLatch;

/**
 * 分布式锁
 */
public class Lock {

  Logger logger = LoggerFactory.getLogger(Lock.class);

  ZooKeeper zooKeeper;

  String dir = "/ycy/lock";

  String prefix = "dq-";

  CountDownLatch countDownLatch;

  String newNode;


  public Lock() throws IOException {
    this.zooKeeper = new ZooKeeper("10.211.55.3:2182,10.211.55.3:2183,10.211.55.3:2184"
            , 60000, null);
  }


  public void tryLock() throws InterruptedException, KeeperException {
    try {
      //注册一个临时节点 必须是临时节点 ，因为如果创建的永久节点，客服端连接断开后，这个节点，可能就变成了死锁
      newNode = zooKeeper.create(dir + "/" + prefix, "1".getBytes()
              , ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
//      logger.info(newNode);
      System.out.println("创建一个节点" + newNode);
      if (newNode != null) {

//        String substring = newNode.substring(prefix.length() - 1);

        //获取所有节点  这个节点是无序的  拿到之后 自己排一下序列
        List<String> children = zooKeeper.getChildren(dir, false);

        Map<String, String> treeMap = new TreeMap<String, String>();

        for (String child : children) {
          treeMap.put(child, child);
        }

        children = new ArrayList<>(treeMap.keySet());

        if ((dir + "/" + children.get(0)).equalsIgnoreCase(newNode)) {
          //创建的节点，如果是头部节点那么，可以执行同步代码块

        } else {
          // (获取前驱节点 注册一个事件 这个思路不对) ,应该是获取节点中，最小的那个节点和当前比较
//          String expecPre = null;

          //获取前驱节点
          String pre = null;
          for (String child : children) {
            if ((dir + "/" + child).equalsIgnoreCase(newNode)) {
              break;
            }
            pre = child;
          }

          countDownLatch = new CountDownLatch(1);
          //监听前驱节点 （这里用exists api 即可，不需要用getData（））
          Stat exists = zooKeeper.exists(dir + "/" + pre, new Watcher() {
            @Override
            public void process(WatchedEvent event) {
              System.out.println(Thread.currentThread().getName() + "接收到前驱节点 删除事件" + event);
              //回调
              countDownLatch.countDown();
            }
          });

          if (exists != null) {
            countDownLatch = new CountDownLatch(1);
            //阻塞
            countDownLatch.await();
          }

        }

      } else {
        //重试

      }
    } catch (KeeperException | InterruptedException e) {
      throw e;
    }

  }


  public void release() {
    try {
      this.zooKeeper.delete(newNode, -1);
      System.out.println("删除节点" + newNode);
    } catch (InterruptedException | KeeperException e) {
      e.printStackTrace();
    }
  }

  public static void main(String[] args) {

    try {
      Lock lock = new Lock();

      lock.tryLock();

//      lock.release();

      System.out.println("释放");

    } catch (IOException | InterruptedException | KeeperException e) {
      e.printStackTrace();
    }


  }

}
